package com.anxin.act.utils;

import com.anxin.act.task.dao.ActTaskDao;
import com.anxin.act.task.entity.ViewHiTask;
import com.anxin.act.task.entity.WfActHiComment;
import com.anxin.act.task.service.ActDockingService;
import com.anxin.act.task.service.ActTaskService;
import com.anxin.act.task.service.ViewHiTaskService;
import com.anxin.act.task.service.WfActHiCommentService;
import com.anxin.act.wfEntrustTask.dao.WfEntrustTaskDao;
import com.anxin.common.utils.IdGen;
import com.anxin.common.utils.ListUtils;
import com.anxin.common.utils.LogUtils;
import com.anxin.common.utils.StringUtils;
import com.anxin.common.utils.spring.SpringUtils;
import com.anxin.common.utils.sys.UserUtils;
import com.anxin.sys.system.entity.SysUser;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.el.ExpressionManager;
import org.activiti.engine.impl.el.JuelExpression;
import org.activiti.engine.impl.juel.Node;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
import org.activiti.engine.impl.variable.StringType;
import org.activiti.engine.task.Task;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 工作流任务工具类
 * @author: liuxiangyu
 * @date: 2020/8/9 20:40
 */
public class ActTaskUtils {

    private static TaskService taskService = SpringUtils.getBean(TaskService.class);

    private static HistoryService historyService = SpringUtils.getBean(HistoryService.class);

    private static ActTaskService actTaskService = SpringUtils.getBean(ActTaskService.class);

    private static WfActHiCommentService wfActHiCommentService = SpringUtils.getBean(WfActHiCommentService.class);

    private static ViewHiTaskService viewHiTaskService = SpringUtils.getBean(ViewHiTaskService.class);

    private static ActDockingService actDockingService = SpringUtils.getBean(ActDockingService.class);

    private static WfEntrustTaskDao wfEntrustTaskDao = SpringUtils.getBean(WfEntrustTaskDao.class);

    private static ActTaskDao actTaskDao = SpringUtils.getBean(ActTaskDao.class);


    /**
     * 获取节点对应的key和流程实例ID查询待办任务
     * @param taskKey
     * @param procInsId
     */
    public static Task getTask(String taskKey, String procInsId){
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).taskDefinitionKey(taskKey).active().list();
        if (taskList.size() > 0){
            return taskList.get(0);
        }

        return null;
    }

    /**
     * 获取节点对应的key和流程实例ID查询待办任务
     * @param taskKey
     * @param procInsId
     */
    public static HistoricTaskInstance getHiTaskByTaskKey(String taskKey, String procInsId){
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(procInsId).taskDefinitionKey(taskKey).list();
        if (historicTaskInstanceList.size() > 0){
            return historicTaskInstanceList.get(0);
        }

        return null;
    }

    /**
     * 根据taskKey查询待办
     * @param taskKey
     * @param procInsId
     * @return
     */
    public static List<Task> getTaskList(String taskKey, String procInsId){
        return taskService.createTaskQuery().processInstanceId(procInsId).taskDefinitionKey(taskKey).active().list();
    }

    /**
     * 获取当前流程实例的待办任务集合
     *
     * @param procInsId
     * @return
     */
    public static List<Task> getCurrentTaskList(String procInsId) {
        return taskService.createTaskQuery().processInstanceId(procInsId).active().list();
    }

    /**
     * 根据taskId查询任务
     * @param taskId 任务ID
     * @return
     */
    public static Task getTask(String taskId){
        return taskService.createTaskQuery().taskId(taskId).includeTaskLocalVariables().singleResult();
    }

    /**
     * 获取历史任务
     * @param taskId 任务ID
     * @return 历史任务对象
     */
    public static HistoricTaskInstance getHiTask(String taskId){
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        return historicTaskInstance;
    }


    /**
     * 根据流程实例ID和taskKey获取历史人物
     * @param taskKey
     * @param procInsId
     * @return
     */
    public static List<HistoricTaskInstance> getHiTask(String taskKey, String procInsId){
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(procInsId).taskDefinitionKey(taskKey).list();
        return list;
    }

    /**
     * 获取流程变量，如果不存在则从历史任务中获取
     * @param task
     * @param key
     * @return
     */
    public static String getTaskLocalVariable(Task task,String key){
        Object value = task.getTaskLocalVariables().get(key);
        if (value != null){
            return value.toString();
        }

        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .taskDefinitionKey(task.getTaskDefinitionKey())
                .processInstanceId(task.getProcessInstanceId())
                .includeTaskLocalVariables()
                .orderByTaskCreateTime().desc()
                .list();

        for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
            if (historicTaskInstance.getTaskLocalVariables().get(key) != null){
                return historicTaskInstance.getTaskLocalVariables().get(key).toString();
            }
        }
        return null;
    }

    /**
     * 获取审批意见
     * @param taskId
     * @return
     */
    public static String getTaskComments(String taskId){
        StringBuffer comment = new StringBuffer();

        ViewHiTask viewHiTask = viewHiTaskService.get(taskId);
        List<WfActHiComment> commentList = wfActHiCommentService.getCommentList(viewHiTask);

        for (WfActHiComment wfActHiComment : commentList) {
            StringUtils.bufferAppend(comment,wfActHiComment.getMessage(),"<br/>");
        }

//        StringBuffer comment = new StringBuffer();
//        List<Comment> taskComments = taskService.getTaskComments(taskId);
//        for (Comment taskComment : taskComments) {
//            StringUtils.bufferAppend(comment,taskComment.getFullMessage(),"<br/>");
//        }

        return comment.toString();
    }

    /**
     * 签收任务
     * @param actId 流程实例ID
     */
    public static void claimTask(String actId){
        List<Task> currentTaskList = ActTaskUtils.getCurrentTaskList(actId);
        for (Task task : currentTaskList) {
            // 当前这个任务所有审批人，包含未签收的
            List<String> assigneeList = ActUtils.getAssigneeByTask(task);
            if (assigneeList.size() == 1){
                ActTaskUtils.claimTask(task.getId(),assigneeList.get(0));
            }
        }
    }

    /**
     * 签收任务并删除其他人待办
     * @param taskId 待办ID
     * @param userName 审批人名称
     */
    public static void claimTaskAndDelOtherTask(String taskId,String userName){
        Task task = ActTaskUtils.getTask(taskId);
        List<String> assigneeList = ActUtils.getAssigneeByTask(task);
        for (String assignee : assigneeList) {
            if (!userName.equals(assignee)){
                actDockingService.delTaskByUserName(taskId,assignee);
            }
        }
        ActTaskUtils.claimTask(task.getId(),userName);
    }

    /**
     * 签收任务
     * @param taskId 任务ID
     * @param userName 用户登录名
     */
    public static void claimTask(String taskId,String userName){
        taskService.claim(taskId,userName);
    }

    /**
     * 获取流程的最后一个任务
     * @param actId
     * @return
     */
    public static HistoricTaskInstance getLastTask(String actId){
        return historyService.createHistoricTaskInstanceQuery().processInstanceId(actId).includeTaskLocalVariables().orderByTaskCreateTime().desc().orderByHistoricTaskInstanceEndTime().desc().list().get(0);
    }

    /**
     * 获取审批人集合
     * @return
     */
    public static List<String> getAssigneeList(String actId,String taskKey){
        List<String> assigneeList = new ArrayList<>();
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(actId).taskDefinitionKey(taskKey).orderByTaskCreateTime().desc().list();

        if (historicTaskInstanceList.size() > 0){
            HistoricTaskInstance historicTaskInstance = historicTaskInstanceList.get(0);

            for (HistoricTaskInstance taskInstance : historicTaskInstanceList) {
                if (historicTaskInstance.getStartTime().getTime() == taskInstance.getStartTime().getTime() || (historicTaskInstance.getStartTime().getTime() - taskInstance.getStartTime().getTime() <5000) || (taskInstance.getStartTime().getTime() - historicTaskInstance.getStartTime().getTime()  > -5000)){
                    SysUser sysUser = UserUtils.getUserByUserName(taskInstance.getAssignee());
                    if (sysUser != null){
                        ListUtils.addEliminateRepetitive(assigneeList,sysUser.getId());
                    }
                }
            }
        }
        return assigneeList;
    }

    /**
     * 获取当前流程实例的待办任务
     *
     * @param procInsId
     * @return
     */
    public static TaskEntity getCurrentTask(String procInsId) {
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).active().list();
        if (taskList.size() > 0) {
            return (TaskEntity) taskList.get(0);
        }
        return null;
    }

    /**
     * 根据taskId挂起任务
     * @param actId 流程实例ID
     * @param taskKey 流程Key
     */
    public void suspendTaskByKey(String actId,String taskKey){
        List<Task> taskList = ActTaskUtils.getTaskList(taskKey, actId);

    }

    /**
     * 根据TaskId挂起任务
     * @param taskId 任务ID
     */
    public void suspendTaskById(String taskId){

    }

    /**
     * 根据taskId激活任务
     * @param actId 流程实例ID
     * @param taskKey 流程Key
     */
    public void activateTaskByKey(String actId,String taskKey){

    }

    /**
     * 根据TaskId激活任务
     * @param taskId 任务ID
     */
    public void activateTaskById(String taskId){

    }


    /**
     * 根据用户ID查询这个用户的任务都委托给了谁
     * @return
     */
    public static List<String> findBeEntrustUserName(String userId){
        SysUser user = UserUtils.getUser(userId);
        List<String> userNameList = wfEntrustTaskDao.findBeEntrustUserName(userId);
        if (!userNameList.contains(user.getUserName())){
            userNameList.add(user.getUserName());
        }
        return userNameList;
    }

    /**
     * 根据用户ID查询把待办委托给当前用户的用户 有参方法
     * @return
     */
    public static List<String> findEntrustUserName(String userId){
        SysUser user = UserUtils.getUser(userId);
        List<String> userNameList = wfEntrustTaskDao.findEntrustUserName(userId);
        if (!userNameList.contains(user.getUserName())){
            userNameList.add(user.getUserName());
        }
        return userNameList;
    }

    /**
     * 修改任务的启动时间
     *
     * @param taskId 任务ID
     */
    public static void updateTaskStartTime(String taskId) {
        actTaskDao.updateHiActInstStartTime(taskId);
        actTaskDao.updateHiTaskInstStartTime(taskId);
        actTaskDao.updateRuTaskStartTime(taskId);
    }

    public static String getTaskNodeName(FlowElement flowNode) {
        ExpressionManager expressionManager = new ExpressionManager();
        if (((UserTask) flowNode).getCandidateUsers().size() > 0){
            JuelExpression expression = (JuelExpression) expressionManager.createExpression(((UserTask) flowNode).getCandidateUsers().get(0));
            String className = expression.getClassName();

            String methodName = expression.getMethods().trim();

            Node parameter = expression.getParameter();

            Object bean = SpringUtils.getBean(className);

            Class<?> mClass = bean.getClass();
            ExecutionEntity executionEntity = ActTaskUtils.getExecutionEntity();
            try {
                Class[] classesType = new Class[parameter.getCardinality()];
                Object[] classesValue = new Object[parameter.getCardinality()];

                for (int i = 0; i < parameter.getCardinality(); i++) {

                    if ("execution".equals(parameter.getChild(i).toString())){
                        classesValue[i] = executionEntity;
                        classesType[i] = DelegateExecution.class;
                    }else {
                        classesValue[i] = parameter.getChild(i).toString().replace("\"","");
                        classesType[i] = String.class;
                    }

                }
                Method method =  mClass.getMethod(methodName,classesType);
                Object invoke = null;
                try {
                    invoke = method.invoke(bean,classesValue);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    LogUtils.error(e.getMessage(),e);
                }
                if (invoke != null){
                    List<SysUser> userListByUserNames = UserUtils.getUserListByUserNames(invoke.toString());
                    if (userListByUserNames.size() > 0){
                        return flowNode.getName() + "("+userListByUserNames.get(0).getNickName()+")" ;
                    }
                }

            } catch (NoSuchMethodException e) {
                LogUtils.error(e.getMessage(),e);
            }
        }


        return flowNode.getName();
    }

    /**
     * 自定义 ExecutionEntity 对象
     * @return
     */
    public static ExecutionEntity getExecutionEntity(){
        ExecutionEntity executionEntity = new ExecutionEntity();
        ExecutionEntity processInstance = new ExecutionEntity();

        SysUser user = UserUtils.getUser();

        List<VariableInstanceEntity> queryVariables = new ArrayList<>();

        VariableInstanceEntity applyUserName = VariableInstanceEntity.create("applyUserName",new StringType(1000),user.getUserName());
        applyUserName.setId(IdGen.uuid());
        queryVariables.add(applyUserName);

        VariableInstanceEntity applyUserId = VariableInstanceEntity.create("applyUserId",new StringType(1000),user.getId());
        applyUserId.setId(IdGen.uuid());
        queryVariables.add(applyUserId);

        VariableInstanceEntity actDataTable = VariableInstanceEntity.create("actDataTable",new StringType(1000),user.getId());
        actDataTable.setId(IdGen.uuid());
        queryVariables.add(actDataTable);

        VariableInstanceEntity actDataId = VariableInstanceEntity.create("actDataId",new StringType(1000),user.getId());
        actDataId.setId(IdGen.uuid());
        queryVariables.add(actDataId);

        processInstance.setQueryVariables(queryVariables);
        executionEntity.setProcessInstance((InterpretableExecution) processInstance);
        return executionEntity;
    }

}
